//
//  ControlFlowGraphLoop.cpp
//  ConstructGccfg2.0
//
//  Created by Bryce Holton on 12/8/12.
//  Copyright (c) 2012 Bryce Holton. All rights reserved.
//

#include <set>
#include "ControlFlowGraph.h"

ControlFlowGraphLoop::ControlFlowGraphLoop(int id) : ControlFlowGraph()
{
    loopId = id;
}
ControlFlowGraphLoop::~ControlFlowGraphLoop()
{
    
}
int ControlFlowGraphLoop::GetLoopId()
{
    return loopId;
}
BasicBlock *ControlFlowGraphLoop::FindLoopExitBlock(set<BasicBlock *> &parentBlockSet)
{
    BasicBlock *loopExit = NULL;
    set<BasicBlock *> testExitBlocks = GetExitChildren(); // This is the set of all blocks after leaving a loop.
    set<BasicBlock *> exitBlocks; // This is the set of all blocks after leaving a loop that are in the calling loop or function.
    
    set_intersection(testExitBlocks.begin(), testExitBlocks.end(),
                     parentBlockSet.begin(), parentBlockSet.end(),
                     inserter(exitBlocks, exitBlocks.begin()));
    for (set<BasicBlock *>::iterator it = exitBlocks.begin(); it != exitBlocks.end(); it++)
    {
        if ((*it)->GetDecendantEdges().size() > 0)
        {
            loopExit = *it;
        }
    }
    
    return loopExit;
}
void ControlFlowGraphLoop::SeverChildrenNotInThisLoop()
{
    set<BasicBlock *> thisBlockSet = ControlFlowGraph::GetBlockSet();
    set<BasicBlock *> testExitBlocks = GetExitChildren(); // This is the set of all blocks after leaving a loop.
    
    for (set<BasicBlock *>::iterator itr = testExitBlocks.begin(); itr != testExitBlocks.end(); itr++)
    {
        if ((*itr)->GetAncestorEdges().size() == 1 && (*itr)->GetDecendantEdges().size() == 0)
        {
            // If a child of this loop has no decendants and it is not in the block list and its only ancestor is the loop
            // Then it is a program exit block.  We need to add it to the loop.
            thisBlockSet.insert(*itr);
        }
        else
        {
            // If a child of this loop has some decendants or maybe more than one ancestor, but it is a child of the loop
            // Then it is a break from the loop.  We need to redirect it to the loop exit.  Unless it is the loop head.
            // This is so we maintain condition nodes inside of a loop.
            vector<Edge<BasicBlock *> *> parentEdges = (*itr)->GetAncestorEdges();
            BasicBlock *thisParent = NULL;
            
            for (unsigned int i = 0; i < parentEdges.size(); i++)
            {
                if ( ( thisParent = FindBlockInSet( parentEdges[i]->GetAncestor()->GetId() ) ) != NULL && thisParent != GetRootBlock() )
                {
                    thisParent->ReplaceChild(**itr, *this->GetExitBlock());
                }
                else if (thisParent == GetRootBlock())
                {
                    thisParent->RemoveChild(**itr);
                }
            }
        }
    }
    this->SetBlockSet(thisBlockSet);
}
set<BasicBlock *> ControlFlowGraphLoop::GetExitChildren()
{
    set<BasicBlock *> blockSet = ControlFlowGraph::GetBlockSet(),
    setOfChildren = ControlFlowGraph::GetSetOfChildrenThisGraph(),
    returnSet;
    
    set_difference(setOfChildren.begin(), setOfChildren.end(),
                   blockSet.begin(), blockSet.end(),
                   inserter(returnSet, returnSet.begin()));
    
    return returnSet;
}
